package com.gframework.mybatis.dao.datasource;

import java.io.Closeable;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Set;
import java.util.function.Supplier;

import javax.sql.DataSource;

import org.springframework.lang.Nullable;

/**
 * 动态数据源连接池操作接口.
 * <p>
 * 动态数据源指的是除过基础配置意外的数据源，如运行时创建的数据源，以及通过其他方式配置的数据源。
 * 这些数据源<strong>不受到spring管理</strong>，而是有此接口自己维护，每个数据源都有一个唯一的名称，通过名称可以取得
 * 数据源，你也可以随时停用数据源、添加数据源、刷新数据源配置等。
 * </p>
 * <p>
 * 此接口是一个抽象接口，不负责数据源的管理，不限制你的数据库连接池类型或者配置方式，以及到底是配置一个dataSoruce或是一个数据库连接池。
 * <strong>你唯一需要注意的就是在使用时注意数据源的加载时间，避免在加载之前就进行了使用。</strong>
 * </p>
 * <p>
 * 例如你有一个数据源表，这个表中存放着其他数据源的信息，那么你就可以通过此接口来管理这些数据源。
 * </p>
 * 
 * @since 1.0.0
 * @author Ghwolf
 */
public interface DynamicDataSourceManager {
	
	/**
	 * 配置一个新的数据源信息.
	 * <p>
	 * <strong>注意：建议使用实现了 {@link Closeable} 接口的数据源，或者本身提供了close方法的数据源，否则可能会无法真正的关闭数据源导致对象残留造成内存溢出。</strong>
	 * </p>
	 * 
	 * @param key 用于描述此数据源的key
	 * @param dataSource 和此key关联的数据源对象，也可以是一个数据库连接池对象
	 * @return 如果key已存在返回false，同时添加失败，否则添加成功返回true
	 * @throws NullPointerException key或dataSource为null，则抛出此异常
	 */
	public boolean register(String key, DataSource dataSource) ;
	/**
	 * 配置一个新的延迟加载的数据源信息.
	 * <p>
	 * <strong>注意：建议使用实现了 {@link Closeable} 接口的数据源，或者本身提供了close方法的数据源，否则可能会无法真正的关闭数据源导致对象残留造成内存溢出。</strong>
	 * </p>
	 * 
	 * @param key 用于描述此数据源的key
	 * @param lazyDataSource 和此key关联的数据源对象延迟加载器
	 * @return 如果key已存在返回false，同时添加失败，否则添加成功返回true
	 * @throws NullPointerException key或dataSource为null，则抛出此异常
	 */
	public boolean register(String key, Supplier<DataSource> lazyDataSource) ;
	/**
	 * 删除一个数据源配置(如果支持close方法，则执行close方法).
	 * <p>
	 * <strong>不会对正在使用数据库连接的程序造成影响，在数据库连接都关闭且数据源也关闭之后，会在适当的时候被回收</strong>。
	 * </p>
	 * @param key 要删除的数据源的key，可以为null，为null则返回false
	 * @return 如果删除失败返回false（key为null，数据源不存在等，具体与实现有关，有些甚至可能在使用中无法删除），否则删除成功返回true。
	 */
	public boolean remove(@Nullable String key) ;
	
	/**
	 * 判断制定key值的数据源是否存在.
	 * @param key 要判断的key，如果为null则返回false
	 * @return 如果存在则返回true，否则返回false。注意：返回true也不代表一定能用，可能数据源已经占满或其他问题。
	 */
	public boolean contains(@Nullable String key) ;
	
	/**
	 * 取得当前存在可以使用的数据源key值集合
	 * @return 返回当前可用的key集合，如果没有返回null
	 */
	public Set<String> getCurrentKeys();
	
	/**
	 * 每次调用此方法，都会取得一个【新的】空闲的数据库连接对象.
	 * <p>
	 * 获取过程可能会抛出异常如无可用连接，具体与注册进来的数据库连接池有关。
	 * </p>
	 * @param key 要取得的数据源的key
	 * @return 如果数据源不存在，则抛出异常，否则尝试取得一个新的数据库连接对象。
	 * @throws SQLException 获取数据库连接时发生异常
	 */
	public Connection openConnection(String key) throws SQLException;
	
	/**
	 * 每次调用此方法，都会取得一个【新的】空闲的数据库连接对象.
	 * <p>
	 * 获取过程可能会抛出异常如无可用连接，具体与注册进来的数据库连接池有关。
	 * </p>
	 * @param key 要取得的数据源的key
	 * @param username 用户名
	 * @param password 密码
	 * @return 如果数据源不存在，则抛出异常，否则尝试取得一个新的数据库连接对象。
	 * @throws SQLException 获取数据库连接时发生异常
	 */
	public Connection openConnection(String key,String username,String password) throws SQLException;
	

}
